iT邦幫忙

2023 iThome 鐵人賽

DAY 26
0
SideProject30

行事曆不再NG:Notion API&Google Calendar跨平台整合發想系列 第 26

Day 26 Notion API & Google Calendar API Integration - Google Calendar List Refactor

  • 分享至 

  • xImage
  •  

照慣例,先上spec

/googleCalendar/getGoogleCalendarEventList/{calendarId}:
    get:
      summary: Get a list of events from Google Calendar
      parameters:
        - name: calendarId
          in: path
          required: true
          description: ID of the Google Calendar to retrieve events from
          schema:
            type: string
        - name: timeMin
          in: query
          required: false
          description: Lower bound (exclusive) for an event's end time to filter by.
          schema:
            type: string
        - name: timeMax
          in: query
          required: false
          description: Upper bound (exclusive) for an event's start time to filter by
          schema:
            type: string
      responses:
        '200':
          description: List of events from Google Calendar
        '404':
          description: Calendar not found

難得今天用的是GET🤪

Main

func main() {
	r := gin.Default()

	c := controller.NewController()

	v1 := r.Group("/api/v1")
	{
		googleCalendar := v1.Group("/googleCalendar")
		{
			googleCalendar.GET("/getEventList/:calendarId", c.GetGoogleCalendarEventList)
		}
...

這邊跟原本的內容差不多,就只是加上path中有calendarId

Controller

這邊的改動有點多,所以我也是先一段一段講

// GetGoogleCalendarEventList godoc
//
//	@Summary		Get Google Calendar Event List
//	@Description	Get a list of events from Google Calendar
//	@Tags			googleCalendar
//	@Accept			json
//	@Produce		json
//	@Param			calendarId	path	string	true	"Database ID"
//	@Param			timeMin	query	string	false	"timeMin"
//	@Param			timeMax query	string	false	"timeMax"
//	@Success		200		{array}		responseModel.CalendarEvents "success"
//	@Failure		400		{string}	string			"fail"
//	@Failure		404		{string}	string			"Calendar not found"
//	@Router		/api/v1/googleCalendar/getEventList/{calendarId} [get]

先從swaggo的內容開始講起,跟前面不同的是這邊多個兩個query

這兩個query主要是用來限制google calendar搜尋的內容

因為後續sync的時候,目前的規劃是只會sync一天的內容

以防要比對太多東西運算量有點大,在notion的地方有filter可以用

而在google calendar這邊就要用timeMax跟timeMin來限制區間

func (c *Controller) GetGoogleCalendarEventList(ctx *gin.Context) {
	configHandler := util.NewConfigHandler()
	auth := configHandler.GetSecretConfig().Get("GoogleSecretKey")

	calendarId := ctx.Param("calendarId")
	calendarService, err := calendar.NewService(ctx, option.WithAPIKey(auth.(string)))
	if err != nil {
		panic(err)
	}
...

code一開始的改動只有增加讀取calendarId這個參數

func (c *Controller) GetGoogleCalendarEventList(ctx *gin.Context) {
	...
	timeMin := ctx.Request.URL.Query().Get("timeMin")
	checkTimeFormat(timeMin, "Error parsing timeMin:", ctx)

	timeMax := ctx.Request.URL.Query().Get("timeMax")
	checkTimeFormat(timeMax, "Error parsing timeMax:", ctx)
	...
}

func checkTimeFormat(timeStr string, errMsg string, ctx *gin.Context) {
	if timeStr != "" {
		_, err := time.Parse("2006-01-02T15:04:05+00:00", timeStr)
		if err != nil {
			ctx.JSON(http.StatusBadRequest, gin.H{errMsg: err.Error()})
		}
	}
}

由於讓上面的時間用string的方式來讀取,所以這邊透過一個checkTimeFormat來確定這兩個時間的內容format是正常的,如果有值才會確定是不是正常的

func (c *Controller) GetGoogleCalendarEventList(ctx *gin.Context) {
	...
	eventList := &calendar.Events{}
	switch {
		case timeMin != "" && timeMax != "":
			eventList, err = calendarService.Events.List(calendarId).TimeMin(timeMin).TimeMax(timeMax).Do()
		case timeMax != "":
			eventList, err = calendarService.Events.List(calendarId).TimeMax(timeMax).Do()
		case timeMin != "":
			eventList, err = calendarService.Events.List(calendarId).TimeMin(timeMin).Do()
		default:
			eventList, err = calendarService.Events.List(calendarId).Do()
	}
	if err != nil {
		panic(err)
	}
	...
}

接著用一個switch來確定有沒有timeMin或timeMax的值,有的話才要使用這個function,沒有的話用了會跳500 error

func (c *Controller) GetGoogleCalendarEventList(ctx *gin.Context) {
	...
	var response responseModel.CalendarEvents
	response.Kind = eventList.Kind
	response.Etag = eventList.Etag
	response.Summary = eventList.Summary
	response.Description = eventList.Description
	response.Updated = eventList.Updated
	response.TimeZone = eventList.TimeZone
	response.AccessRole = eventList.AccessRole
	response.NextSyncToken = eventList.NextSyncToken

	for _, item := range eventList.Items {
		response.Items = append(response.Items, responseModel.Event{
			Kind:     item.Kind,
			Etag:     item.Etag,
			Id:       item.Id,
			Status:   item.Status,
			HtmlLink: item.HtmlLink,
			Created:  item.Created,
			Updated:  item.Updated,
			Summary:  item.Summary,
			Creator: struct {
				Email string `json:"email"`
			}{
				Email: item.Creator.Email,
			},
			Organizer: struct {
				Email       string `json:"email"`
				DisplayName string `json:"displayName"`
				Self        bool   `json:"self"`
			}{
				Email:       item.Organizer.Email,
				DisplayName: item.Organizer.DisplayName,
				Self:        item.Organizer.Self,
			},
			Start: struct {
				DateTime string `json:"dateTime"`
				TimeZone string `json:"timeZone"`
			}{
				DateTime: item.Start.DateTime,
				TimeZone: item.Start.TimeZone,
			},
			End: struct {
				DateTime string `json:"dateTime"`
				TimeZone string `json:"timeZone"`
			}{
				DateTime: item.End.DateTime,
				TimeZone: item.End.TimeZone,
			},
			ICalUID:   item.ICalUID,
			EventType: item.EventType,
		})
	}
	ctx.JSON(http.StatusOK, eventList)
	...
}

接著要把google calendar的內容接回來,這邊主要是要把calendar.Events的內容接到response的內容

Response

package responseModel

type Event struct {
	Kind     string `json:"kind"`
	Etag     string `json:"etag"`
	Id       string `json:"id"`
	Status   string `json:"status"`
	HtmlLink string `json:"htmlLink"`
	Created  string `json:"created"`
	Updated  string `json:"updated"`
	Summary  string `json:"summary"`
	Creator  struct {
		Email string `json:"email"`
	} `json:"creator"`
	Organizer struct {
		Email       string `json:"email"`
		DisplayName string `json:"displayName"`
		Self        bool   `json:"self"`
	} `json:"organizer"`
	Start struct {
		DateTime string `json:"dateTime"`
		TimeZone string `json:"timeZone"`
	} `json:"start"`
	End struct {
		DateTime string `json:"dateTime"`
		TimeZone string `json:"timeZone"`
	} `json:"end"`
	ICalUID   string `json:"iCalUID"`
	Sequence  int    `json:"sequence"`
	EventType string `json:"eventType"`
}

type CalendarEvents struct {
	Kind             string     `json:"kind"`
	Etag             string     `json:"etag"`
	Summary          string     `json:"summary"`
	Description      string     `json:"description"`
	Updated          string     `json:"updated"`
	TimeZone         string     `json:"timeZone"`
	AccessRole       string     `json:"accessRole"`
	DefaultReminders []struct{} `json:"defaultReminders"`
	NextSyncToken    string     `json:"nextSyncToken"`
	Items            []Event    `json:"items"`
}

這邊也是根據google calendar打回來的內容,將json轉成golang的struct

update-swagger.sh

#!/bin/bash
export PATH="$PATH:$(go env GOPATH)/bin"
export GO111MODULE=on

# rm -f -r ../assets/swagger/docs
rm -f -r ./docs/swagger/docs

# go get -u github.com/swaggo/swag/cmd/swag
go mod download

swag init -o ./docs/swagger/docs --ot json,yaml

echo "Suceessfully generated swagger docs."

在update-swagger的時候有時候會說找不到swag,所以這邊加了兩行處理golang變數的內容

如果有出現一樣的錯誤可以參考

今天就先不demo了,明天要開始串接這幾隻api

主要是先打google calendar list,再打query notion db

這兩隻api的區間都設定在當天00:00:00到當前的時間

然後比對event的內容,如果有少的,就用create notion page來新增項目到notion db中


上一篇
Day 25 Notion API & Google Calendar API Integration - Create Notion Page
下一篇
Day 27 Notion API & Google Calendar API Integration - Sync Google Calendar to Notion
系列文
行事曆不再NG:Notion API&Google Calendar跨平台整合發想30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言